package io.github.krosai.openai.options

import io.github.krosai.core.chat.function.FunctionCall
import io.github.krosai.core.chat.function.FunctionCallOptions
import io.github.krosai.core.chat.prompt.ChatOptions
import io.github.krosai.openai.api.ChatCompletionRequest

data class OpenAiChatOptions(

    /**
     * ID of the model to use.
     */
    var model: String = "gpt-4o",

    /**
     * Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing
     * frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim.
     */
    var frequencyPenalty: Float? = null,

    /**
     * Modify the likelihood of specified tokens appearing in the completion. Accepts a JSON object
     * that maps tokens (specified by their token ID in the tokenizer) to an associated bias value from -100 to 100.
     * Mathematically, the bias is added to the logits generated by the model prior to sampling. The exact effect will
     * vary per model, but values between -1 and 1 should decrease or increase likelihood of selection; values like -100
     * or 100 should result in a ban or exclusive selection of the relevant token.
     */
    var logitBias: Float? = null,

    /**
     * Whether to return log probabilities of the output tokens or not. If true, returns the log probabilities
     * of each output token returned in the 'content' of 'message'.
     */
    var logProbs: Boolean? = null,

    /**
     * An integer between 0 and 5 specifying the number of most likely tokens to return at each token position,
     * each with an associated log probability. 'logprobs' must be set to 'true' if this parameter is used.
     */
    var topLogprobs: Int? = null,

    /**
     * The maximum number of tokens to generate in the chat completion. The total length of input
     * tokens and generated tokens is limited by the model's context length.
     */
    var maxTokens: Int? = null,

    /**
     * How many chat completion choices to generate for each input message. Note that you will be charged based
     * on the number of generated tokens across all of the choices. Keep n as 1 to minimize costs.
     */
    var n: Int? = null,

    /**
     * Number between -2.0 and 2.0. Positive values penalize new tokens based on whether they
     * appear in the text so far, increasing the model's likelihood to talk about new topics.
     */
    var presencePenalty: Float? = null,

    /**
     * An object specifying the format that the model must output. Setting to { "type":
     * "json_object" } enables JSON mode, which guarantees the message the model generates is valid JSON.
     */
    var responseFormat: ChatCompletionRequest.ResponseFormat? = null,

    /**
     * Options for streaming response. Included in the API only if streaming-mode completion is requested.
     */
    var streamOptions: ChatCompletionRequest.StreamOptions? = null,

    /**
     * This feature is in Beta. If specified, our system will make a best effort to sample
     * deterministically, such that repeated requests with the same seed and parameters should return the same result.
     * Determinism is not guaranteed, and you should refer to the system_fingerprint response parameter to monitor
     * changes in the backend.
     */
    var seed: String? = null,

    /**
     * Up to 4 sequences where the API will stop generating further tokens.
     */
    var stop: List<String>? = null,

    /**
     * What sampling temperature to use, between 0 and 1. Higher values like 0.8 will make the output
     * more random, while lower values like 0.2 will make it more focused and deterministic. We generally recommend
     * altering this or top_p but not both.
     */
    override var temperature: Float = 0.7f,

    /**
     * An alternative to sampling with temperature, called nucleus sampling, where the model considers the
     * results of the tokens with top_p probability mass. So 0.1 means only the tokens comprising the top 10%
     * probability mass are considered. We generally recommend altering this or temperature but not both.
     */
    override var topP: Float? = null,

    override var topK: Int? = null,

    /**
     * A list of tools the model may call. Currently, only functions are supported as a tool. Use this to
     * provide a list of functions the model may generate JSON inputs for.
     */
    var tools: List<ChatCompletionRequest.FunctionTool>? = null,

    /**
     * Controls which (if any) function is called by the model. none means the model will not call a
     * function and instead generates a message. auto means the model can pick between generating a message or calling a
     * function. Specifying a particular function via {"type: "function", "function": {"name": "my_function"}} forces
     * the model to call that function. none is the default when no functions are present. auto is the default if
     * functions are present. Use the {@link ToolChoiceBuilder} to create a tool choice object.
     */
    var toolChoice: String? = null,

    /**
     * A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse.
     */
    var user: String? = null,

    /**
     * OpenAI Tool Function Callbacks to register with the ChatModel.
     * For Prompt Options the functionCallbacks are automatically enabled for the duration of the prompt execution.
     * For Default Options the functionCallbacks are registered but disabled by default. Use the enableFunctions to set the functions
     * from the registry to be used by the ChatModel chat completion requests.
     */
    override var functionCalls: MutableList<FunctionCall> = mutableListOf(),

    /**
     * List of functions, identified by their names, to configure for function calling in
     * the chat completion requests.
     * Functions with those names must exist in the functionCallbacks registry.
     * The {@link #functionCallbacks} from the PromptOptions are automatically enabled for the duration of the prompt execution.
     *
     * Note that function enabled with the default options are enabled for all chat completion requests. This could impact the token count and the billing.
     * If the functions is set in a prompt options, then the enabled functions are only active for the duration of this prompt execution.
     */
    override var functionNames: MutableSet<String> = mutableSetOf()

): ChatOptions, FunctionCallOptions {
    
    override fun copy(): OpenAiChatOptions {
        return this.copy(
            model = model,
            frequencyPenalty = frequencyPenalty,
            logitBias = logitBias,
            logProbs = logProbs,
            topLogprobs = topLogprobs,
            maxTokens = maxTokens,
            n = n,
            presencePenalty = presencePenalty,
            responseFormat = responseFormat,
            streamOptions = streamOptions,
            seed = seed,
            stop = stop,
            temperature = temperature,
            topP = topP,
            topK = topK,
            tools = tools,
            toolChoice = toolChoice,
            user = user,
            functionCalls = functionCalls.toMutableList(),
            functionNames = functionNames.toMutableSet()
        )
    }
}